#include "nosal/log/internal/log_manager.h"
#include "nosal/log/logger.h"
//#include "contextid_matcher.h"
#include "gtest/gtest.h"

using namespace ::testing;
using namespace netaos::nosal::log;
using LogManager = netaos::nosal::log::internal::LogManager;

namespace
{
constexpr char mappedInternalCtxId[]{"XXXX"};
}  // namespace

struct LogManagerInitTest : Test
{
    const char* const appId{"TEST"};
    const char* const description{"Unit test app"};
    const LogLevel logLevel{LogLevel::kDebug};
    const LogMode logMode{LogMode::kRemote};
};

TEST_F(LogManagerInitTest, defaultCtorShouldDoNothing)
{
    LogManager logManager;
}

TEST_F(LogManagerInitTest, shouldInitializeSlog2)
{
    LogManager logManager;

    logManager.Initialize(appId, description, logLevel, logMode, "");
}

struct LogManagerBaseTest : Test
{
    LogManager logManager;
};

TEST_F(LogManagerBaseTest, createLogContextShouldReturnContextWithRequestedId)
{
    const auto ctxId{"CTXT"};
    const auto ctxDescr{"Logger"};
    const auto ctxLogLevel{LogLevel::kVerbose};

    auto& logger = logManager.CreateLogContext(ctxId, ctxDescr, ctxLogLevel);
}

TEST_F(LogManagerBaseTest, shouldCreateLogContextWithIdAboveFourCharacters)
{
    const auto ctxId{"ABCDEFGHIJK"};
    const auto ctxDescr{"Logger with long id"};
    const auto ctxLogLevel{LogLevel::kDebug};

    auto& logger = logManager.CreateLogContext(ctxId, ctxDescr, ctxLogLevel);
}

struct LogManagerCreateContextTest : Test
{
    LogManagerCreateContextTest()
    {
        //expectCreateInternalLogger();
    }

    ~LogManagerCreateContextTest()
    {
        //expectCleanupDltLib();
    }
/*
    template <typename TExc>
    void expectRegisterContextThrows(const char* contextId, ara::log::LogLevel ctxtLogLevel, const TExc& exc)
    {
        EXPECT_CALL(
            dltMock, dlt_register_context_ll_ts(_, StrEq(contextId), _, static_cast<DltLogLevelType>(ctxtLogLevel), _))
            .WillOnce(Throw(exc));
    }
    */
    LogManager logManager;
    const char* const internalCtxId{"INTM"};
};

TEST_F(LogManagerCreateContextTest, shouldReturnContextXXXX_whenIdEqualToInternalContextId)
{
    const auto ctxLogLevel{LogLevel::kDebug};

   // expectRegisterContext(mappedInternalCtxId, ctxLogLevel);

    auto& logger = logManager.CreateLogContext(internalCtxId, "Logger with reserved internal id", ctxLogLevel);
   // verifyLoggerContextId(logger, mappedInternalCtxId);
}

TEST_F(LogManagerCreateContextTest, shouldNotCreateDuplicationWithSameContextId)
{
    const auto ctxId{"ABCD"};
    const auto ctxLogLevel{LogLevel::kDebug};
    const auto otherCtxtLogLevel{LogLevel::kError};

   // expectRegisterContext(ctxId, ctxLogLevel);

    auto& logger = logManager.CreateLogContext(ctxId, "ABCD logger", ctxLogLevel);
    auto& otherLogger = logManager.CreateLogContext(ctxId, "ABCD logger duplicated", otherCtxtLogLevel);
   // verifyLoggerContextId(otherLogger, ctxId);
    ASSERT_EQ(&logger, &otherLogger);
}

TEST_F(LogManagerCreateContextTest, shouldNotCreateDuplicationWithSameContextIdAboveFourCharactersLong)
{
    const auto ctxId{"ABCDEFGHIJKLMNOPQ"};
    const auto ctxLogLevel{LogLevel::kDebug};

   // expectRegisterContext(ctxId, ctxLogLevel);

    auto& logger = logManager.CreateLogContext(ctxId, "Logger with long id", ctxLogLevel);
    auto& otherLogger = logManager.CreateLogContext(ctxId, "Logger with long id duplicated", ctxLogLevel);
   // verifyLoggerContextId(otherLogger, "ABCD");
    ASSERT_EQ(&logger, &otherLogger);
}

TEST_F(LogManagerCreateContextTest, shouldNotCreateDuplication_whenIdEqualToInternalContextId)
{
    const auto ctxLogLevel{LogLevel::kDebug};

   // expectRegisterContext(mappedInternalCtxId, ctxLogLevel);
    auto& logger = logManager.CreateLogContext(internalCtxId, "Logger with reserved internal id", ctxLogLevel);

    auto& otherLogger = logManager.CreateLogContext(internalCtxId, "Logger duplicated", ctxLogLevel);
    ASSERT_EQ(&logger, &otherLogger);
}

TEST_F(LogManagerCreateContextTest, shouldReturnInternalContext_whenSystemErrorExceptionThrown)
{
    const auto ctxId{"A"};
    const auto ctxLogLevel{LogLevel::kDebug};

   // expectRegisterContextThrows(ctxId, ctxLogLevel, std::system_error{});

    auto& logger = logManager.CreateLogContext(ctxId, "Logger creation failure", ctxLogLevel);
   // verifyLoggerContextId(logger, internalCtxId);
}

TEST_F(LogManagerCreateContextTest, shouldReturnInternalContext_whenBadAllocExceptionThrown)
{
    const auto ctxId{"AB"};
    const auto ctxLogLevel{LogLevel::kInfo};

   // expectRegisterContextThrows(ctxId, ctxLogLevel, std::bad_alloc{});

    auto& logger = logManager.CreateLogContext(ctxId, "Logger creation failure", ctxLogLevel);
   // verifyLoggerContextId(logger, internalCtxId);
}

TEST_F(LogManagerCreateContextTest, shouldReturnInternalContext_whenSomeExceptionThrown)
{
    const auto ctxId{"ABC"};
    const auto ctxLogLevel{LogLevel::kWarn};

   // expectRegisterContextThrows(ctxId, ctxLogLevel, 42);

    auto& logger = logManager.CreateLogContext(ctxId, "Logger creation failure", ctxLogLevel);
   // verifyLoggerContextId(logger, internalCtxId);
}
